home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / Beer Goggles Hack / common.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-06-23  |  26.5 KB  |  931 lines

  1. /*
  2.     File:        Common.c
  3.  
  4.     Contains:    HackTV cross-platform common code
  5.  
  6.     Written by:    Gary Woodcock
  7.     Updated by: Brian Friedkin
  8.             
  9.     Copyright:    © 1992-1998 by Apple Computer, Inc.
  10. */
  11. #include <QTML.h>
  12. #include <Endian.h>
  13. #include <Menus.h>
  14. #include <Printing.h>
  15. #include <Script.h>
  16. #include <Scrap.h>
  17. #include <QuickTimeComponents.h>
  18. #include <ImageCodec.h>
  19. #include <ColorPicker.h>
  20. #include "Globals.h"
  21. #include "Common.h"
  22.  
  23. GWorldPtr        gTempFrame = NULL;
  24. QTAtomContainer    gEffectDesc = nil;
  25. ImageSequence    gEffectSequenceID = 0;
  26. ImageDescriptionHandle    gSampleDescription = NULL;
  27. TimeBase        gTimeBase = NULL;
  28. unsigned long    gNumFrames = 0;
  29. unsigned long    gSeconds = 0;
  30. unsigned long    gStartSeconds = 0;
  31. RGBColor        gColorToReplace = { 0, 0, 0 };
  32. RGBColor        gColorToReplaceWith = { 0, 65535, 0 };
  33. Boolean            gParental = false;
  34.  
  35. // Disable warnings associated with "\p" strings
  36. #if TARGET_OS_WIN32
  37. #pragma warning(disable: 4129)
  38. #endif
  39.  
  40. static OSErr XorRectToRgn(Rect *srcRectA, Rect *srcRectB, RgnHandle *destRgn);
  41.  
  42. /* ---------------------------------------------------------------------- */
  43.  
  44. void InitializeSequenceGrabber(void)
  45. {
  46.     ComponentDescription    theDesc;
  47.     ComponentResult            result = noErr;
  48.     GrafPtr                    savedPort;
  49.     Component                sgCompID;
  50.     
  51.     gQuitFlag = false;
  52.     gSeqGrabber = 0L;
  53.     gVideoChannel = 0L;
  54.     gSoundChannel = 0L;
  55.     gMonitorPICT = nil;
  56.     gPrintRec = (THPrint) NewHandleClear (sizeof (TPrint));
  57.     
  58.     // Find and open a sequence grabber
  59.     theDesc.componentType = SeqGrabComponentType;
  60.     theDesc.componentSubType = 0L;
  61.     theDesc.componentManufacturer = 'appl';
  62.     theDesc.componentFlags = 0L;
  63.     theDesc.componentFlagsMask = 0L;    
  64.     sgCompID = FindNextComponent (nil, &theDesc);
  65.     if (sgCompID != 0L)
  66.         gSeqGrabber = OpenComponent (sgCompID);
  67.     
  68.     // If we got a sequence grabber, set it up
  69.     if (gSeqGrabber != 0L)
  70.     {
  71.         // Get the monitor
  72.         CreateMonitorWindow();
  73.         if (gMonitor != nil)
  74.         {
  75.             // Display the monitor window
  76.             GetPort (&savedPort);
  77.             MacSetPort (gMonitor);
  78.             MacMoveWindow(gMonitor, 10, 30 + GetMBarHeight(), 0);
  79.             MacShowWindow (gMonitor);        
  80.  
  81.             // Initialize the sequence grabber
  82.             result = SGInitialize (gSeqGrabber);
  83.             if (result == noErr)
  84.             {
  85.                 gTempFrame = MakeOffscreenGWorld ();
  86.                 gTimeBase = NewTimeBase ();
  87.                 LinkUpSources ();
  88.                 result = SGSetGWorld (gSeqGrabber, gTempFrame, nil);
  89.                 
  90.                 // Get a video channel
  91.                 result = SGNewChannel (gSeqGrabber, VideoMediaType, &gVideoChannel);
  92.                 if ((gVideoChannel != nil) && (result == noErr))
  93.                 {
  94.                     short    width;
  95.                     short    height;
  96.                     
  97.                     gQuarterSize = false;
  98.                     gHalfSize = true;
  99.                     gFullSize = false;
  100.                     
  101.                     result = SGGetSrcVideoBounds (gVideoChannel, &gActiveVideoRect);
  102.                     width = (gActiveVideoRect.right - gActiveVideoRect.left)/*/ 2*/;
  103.                     height = (gActiveVideoRect.bottom - gActiveVideoRect.top)/* / 2*/;
  104.                     SizeWindow (gMonitor, width, height, false);
  105.                     
  106.                     result = SGSetChannelUsage (gVideoChannel, seqGrabPreview | seqGrabRecord | seqGrabPlayDuringRecord);
  107.                     result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  108.                 }
  109.                 
  110.                 // Get a sound channel
  111.                 result = SGNewChannel (gSeqGrabber, SoundMediaType, &gSoundChannel);
  112.  
  113.                 if ((gSoundChannel != nil) && (result == noErr))
  114.                 {
  115.                     if (gSoundChannel != nil)
  116.                     {
  117.                         result = SGSetChannelUsage (gSoundChannel, seqGrabPreview | seqGrabRecord);
  118.                         
  119.                         // Set the volume low to prevent feedback when we start the preview,
  120.                         // in case the mic is anywhere near the speaker.
  121.                         result = SGSetChannelVolume (gSoundChannel, 0x0010);
  122.                     }
  123.                 }
  124.                 
  125.                 // Get the alignment proc (for use when dragging the monitor)
  126.                 result = SGGetAlignmentProc (gSeqGrabber, &gSeqGrabberAlignProc);
  127.             }
  128.             
  129.             // Go!
  130.             if (result == noErr)
  131.                 result = SGStartPreview (gSeqGrabber);
  132.             MacSetPort (savedPort);
  133.         }
  134.     }
  135. }
  136.  
  137. /* ---------------------------------------------------------------------- */
  138.  
  139. // Specify and setup a file to contain this track's data
  140. static ComponentResult SetTrackFile(SGChannel theChannel, StringPtr prompt, StringPtr defaultName)
  141. {
  142.     StandardFileReply        reply;
  143.     ComponentResult        err;
  144.     SGOutput    theOutput;
  145.     AliasHandle    alias = 0;
  146.  
  147.     // Get the destination filename
  148.     StandardPutFile(prompt, defaultName, &reply);
  149.     if (!reply.sfGood)
  150.     {
  151.         err = fnfErr;
  152.         goto bail;
  153.     }
  154.  
  155.     // Make an alias from the filename
  156.     if (err = QTNewAlias(&reply.sfFile, &alias, true)) goto bail;
  157.     
  158.     // Create an output from this file
  159.     if (err = SGNewOutput(gSeqGrabber, (Handle)alias, rAliasType, seqGrabToDisk, &theOutput)) goto bail;
  160.  
  161.     // Associate this output with the specified channel
  162.     if (err = SGSetChannelOutput(gSeqGrabber, theChannel, theOutput)) goto bail;
  163.  
  164. bail:
  165.     if (alias) DisposeHandle((Handle)alias);
  166.     return err;
  167. }
  168.  
  169. /* ---------------------------------------------------------------------- */
  170.  
  171. // Record a movie
  172. void DoRecord(void)
  173. {
  174.     long    err;
  175.     StandardFileReply    reply;
  176.     
  177.     // Stop everything while the dialogs are up
  178.     SGStop(gSeqGrabber);
  179.  
  180.     // Get the destination filename
  181.     StandardPutFile("\pSave new movie file as:", "\pHack.mov", &reply);
  182.     if (!reply.sfGood)
  183.     {
  184.         err = fnfErr;
  185.         goto bail;
  186.     }
  187.     if ((err = SGSetDataOutput(gSeqGrabber, &reply.sfFile, seqGrabToDisk)))
  188.         goto bail;
  189.  
  190.     // Ask use for separate video and sound track files if requested
  191.     if (gSoundChannel && gRecordSound && gVideoChannel && gRecordVideo && gSplitTracks)
  192.     {
  193.         if ((err = SetTrackFile(gVideoChannel, "\pSave video track file as:", "\pHackVideo.trk")))
  194.             goto bail;
  195.         if ((err = SetTrackFile(gSoundChannel, "\pSave sound track file as:", "\pHackSound.trk")))
  196.             goto bail;
  197.     }
  198.  
  199.     // If not recording sound or video, then "disable" those channels
  200.     if (gSoundChannel && !gRecordSound)
  201.         SGSetChannelUsage(gSoundChannel, 0);
  202.     if (gVideoChannel && !gRecordVideo)
  203.         SGSetChannelUsage(gVideoChannel, 0);
  204.  
  205.     // Attempt to recover the preview area obscured by dialogs
  206. #if TARGET_OS_WIN32
  207.     UpdatePort(gMonitor);
  208. #endif
  209.     SGUpdate(gSeqGrabber, 0);
  210.  
  211.     // Make the movie file
  212.     DeleteMovieFile(&reply.sfFile);
  213.     if (err = CreateMovieFile(&reply.sfFile, 'TVOD', smSystemScript,
  214.         createMovieFileDontOpenFile | createMovieFileDontCreateMovie | createMovieFileDontCreateResFile,
  215.         nil, nil)) goto bail;
  216.         
  217.     FlushEvents(mDownMask+mUpMask,0);
  218.     
  219.     // Record!
  220.     if (err = SGStartRecord(gSeqGrabber))
  221.         goto bail;
  222.  
  223.     while (!Button() && (err == noErr))
  224.     {
  225.         err = SGIdle(gSeqGrabber);
  226.     }
  227.  
  228.     // If we recorded until we ran out of space, then allow SGStop to be
  229.     // called to write the movie resource.  The assumption here is that the
  230.     // data output filled up but the disk has enough free space left to
  231.     // write the movie resource.
  232.     if (!((err == dskFulErr) || (err != eofErr)))
  233.         goto bail;
  234.     err = SGStop(gSeqGrabber);
  235.     NoteAlert(kMovieHasBeenRecordedAlertID, 0);
  236.     err = SGStartPreview(gSeqGrabber);
  237.  
  238.     return;
  239.  
  240. bail:
  241.     SGPause(gSeqGrabber, false);
  242.     SGStartPreview(gSeqGrabber);
  243. }
  244.  
  245. /* ---------------------------------------------------------------------- */
  246.  
  247. void DoAboutDialog(void)
  248. {
  249.     short        itemHit;
  250.     DialogPtr    aboutDialog;
  251.  
  252.     aboutDialog = GetNewDialog(kAboutDLOGID, nil, (WindowPtr)-1L);
  253.  
  254.     // Do the boring about dialog
  255.     SetDialogDefaultItem(aboutDialog, 1);
  256.     MacShowWindow(aboutDialog);
  257.     do
  258.     {
  259.         ModalDialog(nil, &itemHit);
  260.     }
  261.     while (itemHit != 1);
  262.     DisposeDialog(aboutDialog);
  263. }
  264.  
  265. /* ---------------------------------------------------------------------- */
  266.  
  267. void DoPageSetup(void)
  268. {
  269.     PrOpen();
  270.     PrStlDialog(gPrintRec);
  271.     PrClose();
  272. }
  273.  
  274. /* ---------------------------------------------------------------------- */
  275.  
  276. void DoPrint(void)
  277. {
  278.     TPPrPort    printPort;
  279.     TPrStatus    printStatus;
  280.     ComponentResult        err;
  281.     Rect        tempRect;
  282.  
  283.     // Copy a frame from the monitor
  284.     if (gMonitorPICT != nil)
  285.         KillPicture (gMonitorPICT);
  286.     gMonitorPICT = nil;
  287.     err = SGGrabPict(gSeqGrabber, &gMonitorPICT, nil, 0, grabPictOffScreen);
  288.     if ((err == noErr) && (gMonitorPICT != nil))
  289.     {
  290.         // Print it
  291.         HLock((Handle) gMonitorPICT);
  292.         PrOpen();
  293.         if (PrJobDialog (gPrintRec))
  294.         {
  295.             printPort = PrOpenDoc (gPrintRec, nil, nil);
  296.             err = PrError();
  297.             PrOpenPage (printPort, 0);
  298.             err = PrError();
  299.  
  300.             tempRect  = (**gMonitorPICT).picFrame;
  301.             tempRect.left = EndianS16_BtoN(tempRect.left);
  302.             tempRect.top = EndianS16_BtoN(tempRect.top);
  303.             tempRect.right = EndianS16_BtoN(tempRect.right);
  304.             tempRect.bottom = EndianS16_BtoN(tempRect.bottom);
  305.             DrawPicture(gMonitorPICT, &tempRect);
  306.  
  307.             PrClosePage (printPort);
  308.             err = PrError();
  309.             PrCloseDoc (printPort);
  310.             err = PrError();
  311.             if ((**gPrintRec).prJob.bJDocLoop == bSpoolLoop)
  312.             {
  313.                 PrPicFile (gPrintRec, 0, 0, 0, &printStatus);
  314.                 err = PrError();
  315.             }
  316.         }
  317.         PrClose();
  318.         err = PrError();
  319.         HUnlock((Handle) gMonitorPICT);
  320.     }
  321. }
  322.  
  323. /* ---------------------------------------------------------------------- */
  324.  
  325. void DoCopyToClipboard(void)
  326. {
  327.     ComponentResult    err;
  328.  
  329.     // Copy a frame from the monitor
  330.     if (gMonitorPICT != nil)
  331.         KillPicture (gMonitorPICT);
  332.     gMonitorPICT = nil;
  333.     err = SGGrabPict (gSeqGrabber, &gMonitorPICT, nil, 0, grabPictOffScreen);
  334.     if ((err == noErr) && (gMonitorPICT != nil))
  335.     {
  336.         err = ZeroScrap();
  337.         HLock ((Handle) gMonitorPICT);
  338.         err = PutScrap (GetHandleSize ((Handle) gMonitorPICT), 'PICT', *(Handle)gMonitorPICT);
  339.         HUnlock ((Handle) gMonitorPICT);
  340.     }
  341. }
  342.  
  343. /* ---------------------------------------------------------------------- */
  344.  
  345. static pascal Boolean
  346. SeqGrabberModalFilterProc (DialogPtr theDialog, EventRecord *theEvent,
  347.     short *itemHit, long refCon)
  348. {
  349.     // Ordinarily, if we had multiple windows we cared about, we'd handle
  350.     // updating them in here, but since we don't, we'll just clear out
  351.     // any update events meant for us
  352.     
  353.     Boolean    handled = false;
  354.     
  355.     if ((theEvent->what == updateEvt) && 
  356.         ((WindowPtr) theEvent->message == (WindowPtr) refCon))
  357.     {
  358.         WindowPtr    wPtr = (WindowPtr) refCon;
  359.         BeginUpdate (wPtr);
  360.         EndUpdate (wPtr);
  361.         handled = true;
  362.     }
  363.     
  364.     return (handled);
  365. }
  366.  
  367. /* ---------------------------------------------------------------------- */
  368.  
  369. void DoVideoSettings(void)
  370. {
  371.     Rect    newActiveVideoRect;
  372.     Rect    adjustedActiveVideoRect;
  373.     Rect    curBounds, curVideoRect, newVideoRect, newBounds;
  374.     short    width, height;
  375.     ComponentResult    err;
  376.     GrafPtr    savedPort;
  377.     RgnHandle    deadRgn;
  378.     SGModalFilterUPP    seqGragModalFilterUPP;
  379.     
  380.     // Get our current state
  381.     err = SGGetChannelBounds (gVideoChannel, &curBounds);
  382.     err = SGGetVideoRect (gVideoChannel, &curVideoRect);
  383.     
  384.     // Pause
  385.     err = SGPause (gSeqGrabber, true);
  386.     
  387.     // Do the dialog thang
  388.     seqGragModalFilterUPP = (SGModalFilterUPP)NewSGModalFilterProc(SeqGrabberModalFilterProc);
  389.     err = SGSettingsDialog(gSeqGrabber, gVideoChannel, 0, 
  390.         nil, 0L, seqGragModalFilterUPP, (long)StripAddress ((Ptr) gMonitor));
  391.     DisposeRoutineDescriptor(seqGragModalFilterUPP);
  392.     
  393.     // What happened?
  394.     err = SGGetVideoRect (gVideoChannel, &newVideoRect);
  395.     err = SGGetSrcVideoBounds (gVideoChannel, &newActiveVideoRect);
  396.  
  397.     // Set up our port
  398.     GetPort (&savedPort);
  399.     MacSetPort (gMonitor);
  400.     
  401.     // Has our active rect changed?
  402.     // If so, it's because our video standard changed (e.g., NTSC to PAL),
  403.     // and we need to adjust our monitor window
  404.     if (!MacEqualRect (&gActiveVideoRect, &newActiveVideoRect))
  405.     {
  406.         if (gFullSize)
  407.         {
  408.             width = newActiveVideoRect.right - newActiveVideoRect.left;
  409.             height = newActiveVideoRect.bottom - newActiveVideoRect.top;
  410.             
  411.             gActiveVideoRect = newActiveVideoRect;
  412.             SizeWindow (gMonitor, width, height, false);
  413.             err = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  414.         }
  415.         else if (gHalfSize)
  416.         {
  417.             width = (newActiveVideoRect.right - newActiveVideoRect.left) / 2;
  418.             height = (newActiveVideoRect.bottom - newActiveVideoRect.top) / 2;
  419.             
  420.             gActiveVideoRect = newActiveVideoRect;
  421.             SizeWindow (gMonitor, width, height, false);
  422.             err = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  423.         }
  424.         else if (gQuarterSize)
  425.         {
  426.             width = (newActiveVideoRect.right - newActiveVideoRect.left) / 4;
  427.             height = (newActiveVideoRect.bottom - newActiveVideoRect.top) / 4;
  428.             
  429.             gActiveVideoRect = newActiveVideoRect;
  430.             SizeWindow (gMonitor, width, height, false);
  431.             err = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  432.         }
  433.     }
  434.     
  435.     // Has our crop changed?
  436.     // This code shows how to be crop video panel friendly
  437.     // Two important things - 
  438.     // 1) Be aware that you might have been cropped and adjust your
  439.     //    video window appropriately
  440.     // 2) Be aware that you might have been adjusted and attempt to
  441.     //    account for this.  Adjusting refers to using the digitizer
  442.     //    rect to "adjust" the active source rect within the maximum
  443.     //    source rect.  This is useful if you're getting those nasty
  444.     //    black bands on the sides of your video display - you can use
  445.     //    the control-arrow key sequence to shift the active source 
  446.     //    rect around when you're in the crop video panel
  447.     
  448.     adjustedActiveVideoRect = gActiveVideoRect;
  449.     if (!MacEqualRect (&curVideoRect, &newVideoRect))
  450.     {
  451.         if ((newVideoRect.left < gActiveVideoRect.left) ||
  452.             (newVideoRect.right > gActiveVideoRect.right) ||
  453.             (newVideoRect.top < gActiveVideoRect.top) ||
  454.             (newVideoRect.bottom > gActiveVideoRect.bottom))
  455.         {
  456.             if (newVideoRect.left < gActiveVideoRect.left)
  457.             {
  458.                 adjustedActiveVideoRect.left = newVideoRect.left;
  459.                 adjustedActiveVideoRect.right -= (gActiveVideoRect.left - newVideoRect.left);
  460.             }
  461.             if (newVideoRect.right > gActiveVideoRect.right)
  462.             {
  463.                 adjustedActiveVideoRect.right = newVideoRect.right;
  464.                 adjustedActiveVideoRect.left += (newVideoRect.right - gActiveVideoRect.right);
  465.             }
  466.             if (newVideoRect.top < gActiveVideoRect.top)
  467.             {
  468.                 adjustedActiveVideoRect.top = newVideoRect.top;
  469.                 adjustedActiveVideoRect.bottom -= (gActiveVideoRect.top - newVideoRect.top);
  470.             }
  471.             if (newVideoRect.bottom > gActiveVideoRect.bottom)
  472.             {
  473.                 adjustedActiveVideoRect.bottom = newVideoRect.bottom;
  474.                 adjustedActiveVideoRect.top += (newVideoRect.bottom - gActiveVideoRect.bottom);
  475.             }
  476.             newBounds = newVideoRect;
  477.             MapRect (&newBounds, &adjustedActiveVideoRect, &(gMonitor->portRect));
  478.         }
  479.         else    // Can't tell if we've been adjusted (digitizer rect is smaller on all sides
  480.                 // than the active source rect)
  481.         {
  482.             newBounds = newVideoRect;
  483.             MapRect (&newBounds, &gActiveVideoRect, &(gMonitor->portRect));
  484.         }
  485.         width = newBounds.right - newBounds.left;
  486.         height = newBounds.bottom - newBounds.top;
  487.         err = SGSetChannelBounds (gVideoChannel, &newBounds);
  488.     }
  489.  
  490.     // Clean out the part of the port that isn't being drawn in
  491.     deadRgn = NewRgn();
  492.     if (deadRgn != nil)
  493.     {
  494.         Rect    boundsRect;
  495.         err = SGGetChannelBounds (gVideoChannel, &boundsRect);
  496.         err = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  497.         EraseRgn (deadRgn);
  498.         DisposeRgn (deadRgn);
  499.     }
  500.  
  501.     MacSetPort (savedPort);
  502.     
  503. #if !TARGET_OS_MAC
  504.     // This is necessary, for now, to get the grab to start again afer the
  505.     // dialog goes away.  For some reason the video destRect never gets reset to point
  506.     // back to the monitor window.
  507.     SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  508. #endif
  509.  
  510.     // The pause that refreshes
  511.     err = SGPause (gSeqGrabber, false);
  512. }
  513.  
  514. /* ---------------------------------------------------------------------- */
  515.  
  516. void DoSoundSettings(void)
  517. {
  518.     SGModalFilterUPP    seqGragModalFilterUPP;
  519.     ComponentResult        err;
  520.  
  521.     seqGragModalFilterUPP = (SGModalFilterUPP)NewSGModalFilterProc(SeqGrabberModalFilterProc);
  522.     err = SGSettingsDialog (gSeqGrabber, gSoundChannel, 0,
  523.         nil, 0L, seqGragModalFilterUPP, (long) StripAddress ((Ptr) gMonitor));
  524.     DisposeRoutineDescriptor(seqGragModalFilterUPP);
  525. }
  526.  
  527. /* ---------------------------------------------------------------------- */
  528.  
  529. void DoResize(short divisor)
  530. {
  531.     short        width, height;
  532.     GrafPtr        savedPort;
  533.     Rect        curBounds, maxBoundsRect;
  534.     RgnHandle    deadRgn;
  535.     ComponentResult    err;
  536.  
  537.     // New width and height
  538.     width = (gActiveVideoRect.right - gActiveVideoRect.left) / divisor;
  539.     height = (gActiveVideoRect.bottom - gActiveVideoRect.top) / divisor;
  540.     
  541.     gQuarterSize = (divisor == 4 ? true : false);
  542.     gHalfSize = (divisor == 2 ? true : false);
  543.     gFullSize = (divisor == 1 ? true : false);
  544.     
  545.     // Resize the monitor
  546.     GetPort (&savedPort);
  547.     MacSetPort (gMonitor);
  548.     err = SGPause (gSeqGrabber, true);
  549.     err = SGGetChannelBounds (gVideoChannel, &curBounds);
  550.     maxBoundsRect = gMonitor->portRect;
  551.     SizeWindow (gMonitor, width, height, false);
  552.     MapRect (&curBounds, &maxBoundsRect, &(gMonitor->portRect));
  553.     err = SGSetChannelBounds (gVideoChannel, &curBounds);
  554.  
  555.     // Clean out part of port we're not drawing in
  556.     deadRgn = NewRgn();
  557.     if (deadRgn != nil)
  558.     {
  559.         Rect    boundsRect;
  560.  
  561.         err = SGGetChannelBounds (gVideoChannel, &boundsRect);
  562.         err = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  563.         EraseRgn (deadRgn);
  564.         DisposeRgn (deadRgn);
  565.     }
  566.         
  567.     MacSetPort (savedPort);
  568.     err = SGPause (gSeqGrabber, false);
  569. }
  570.  
  571. /* ---------------------------------------------------------------------- */
  572.  
  573. static OSErr XorRectToRgn (Rect *srcRectA, Rect *srcRectB, RgnHandle *destRgn)
  574. {
  575.     RgnHandle    srcRgnA = NewRgn();
  576.     RgnHandle    srcRgnB = NewRgn();
  577.     OSErr        result = noErr;
  578.     
  579.     if ((destRgn != nil) && (*destRgn != nil))
  580.     {
  581.         if ((srcRgnA != nil) &&
  582.             (srcRgnB != nil))
  583.         {
  584.             RectRgn (srcRgnA, srcRectA);
  585.             RectRgn (srcRgnB, srcRectB);
  586.             MacXorRgn (srcRgnA, srcRgnB, *destRgn);
  587.             DisposeRgn (srcRgnA);
  588.             DisposeRgn (srcRgnB);
  589.         }
  590.         else
  591.         {
  592.             result = memFullErr;
  593.         }
  594.     }
  595.     else
  596.     {
  597.         result = nilHandleErr;
  598.     }
  599.     return (result);
  600. }
  601.  
  602. /* ---------------------------------------------------------------------- */
  603.  
  604. #pragma mark -
  605.  
  606. // Create a GWorld that will hold our video - Just hardcode the size for now
  607.  
  608. GWorldPtr MakeOffscreenGWorld (void)
  609. {
  610.     GWorldPtr    gwpOffscreen = NULL;
  611.     Rect        rBounds;
  612.     QDErr        qdeOffscreen = noErr;
  613.     
  614.     SetRect (&rBounds, 0, 0, 720, 480);
  615.     qdeOffscreen = NewGWorld (&gwpOffscreen, 0, &rBounds, NULL, NULL, 0);
  616.     
  617.     if ((qdeOffscreen == noErr) && (gwpOffscreen != NULL)) {
  618.         PixMapHandle    pmhOffscreen = GetGWorldPixMap (gwpOffscreen);
  619.         
  620.         if (pmhOffscreen != NULL) {
  621.             GWorldPtr    oldWorld;
  622.             GDHandle    oldDevice;
  623.             RGBColor    rgbWhite = { 65535, 65535, 65535 };
  624.             RGBColor    rgbBlack = { 0, 0, 0 };
  625.             
  626.             LockPixels (pmhOffscreen);
  627.             
  628.             GetGWorld (&oldWorld, &oldDevice);
  629.             SetGWorld (gwpOffscreen, NULL);
  630.             
  631.             RGBForeColor (&rgbBlack);
  632.             RGBBackColor (&rgbWhite);
  633.             ClipRect (&rBounds);
  634.             EraseRect (&rBounds);
  635.             
  636.             SetGWorld (oldWorld, oldDevice);
  637.         }
  638.     } else {
  639.         gwpOffscreen = NULL;
  640.     }
  641.     
  642.     MakeEffectDescription ();
  643.     gSampleDescription = MakeSampleDescription (kWhichEffect, 720, 480);
  644.     PrepareDecompressionSequence ();
  645.  
  646.     return gwpOffscreen;
  647. }
  648.  
  649.  
  650.  
  651. void MakeEffectDescription (void)
  652. {
  653. //    QTAtomContainer     myEffectDesc = nil;
  654.     OSType    myType;
  655.     OSErr    myErr = noErr;
  656.     long    myLong;
  657.  
  658.     // Create a new, empty effect description
  659.     myErr = QTNewAtomContainer(&gEffectDesc);
  660.  
  661.     // This example is an effect description for an SMPTE effect
  662.     myType = kWhichEffect; //'MoSc';//kEmbossImageFilterType;
  663.     myErr = QTInsertChild(gEffectDesc,
  664.         kParentAtomIsContainer,
  665.                     kParameterWhatName,
  666.                     kParameterWhatID,
  667.                     0,
  668.                     sizeof(myType),
  669.                     &myType,
  670.                     nil);
  671.  
  672.     // Now reference the two sources to be used. These will not be items 
  673.     // in an input map. Instead the source names used will be resolved in
  674.     // the decompression sequence.
  675.     myType = 'srcA';
  676.     myErr = QTInsertChild(gEffectDesc,
  677.                     kParentAtomIsContainer,
  678.                     kEffectSourceName,
  679.                     1,
  680.                     0,
  681.                     sizeof(myType),
  682.                     &myType,
  683.                     nil);
  684.  
  685.  
  686.     myErr = QTInsertChild(gEffectDesc,
  687.                     kParentAtomIsContainer,
  688.                     'ColR',//'MsSz', //'ksiz',
  689.                     1,
  690.                     0,
  691.                     sizeof(gColorToReplace),
  692.                     &gColorToReplace,
  693.                     nil);
  694.  
  695. /*    myErr = QTInsertChild(gEffectDesc,
  696.                     kParentAtomIsContainer,
  697.                     'CoRp',//'MsSz', //'ksiz',
  698.                     2,
  699.                     0,
  700.                     sizeof(gColorToReplaceWith),
  701.                     &gColorToReplaceWith,
  702.                     nil);*/
  703.     // This example uses SMTPE effect number 74, so add a WipeID
  704.     // parameter with the value 74
  705.     myLong = 10; //10;//3;
  706.     myErr = QTInsertChild(gEffectDesc,
  707.                     kParentAtomIsContainer,
  708.                     'Smlr',//'MsSz', //'ksiz',
  709.                     2,
  710.                     0,
  711.                     sizeof(myLong),
  712.                     &myLong,
  713.                     nil);
  714.  
  715.     if (gParental) {
  716.         myLong = 0;
  717.     } else {
  718.         myLong = 1; //10;//3;
  719.     }
  720.     myErr = QTInsertChild(gEffectDesc,
  721.                     kParentAtomIsContainer,
  722.                     'blur',//'MsSz', //'ksiz',
  723.                     3,
  724.                     0,
  725.                     sizeof(myLong),
  726.                     &myLong,
  727.                     nil);
  728. }
  729.  
  730.  
  731. ImageDescriptionHandle MakeSampleDescription (OSType theEffectType, short theWidth,
  732.     short theHeight)
  733. {
  734.     ImageDescriptionHandle mySampleDesc = nil;
  735.     OSErr myErr = noErr;
  736.  
  737.     // create a new sample description
  738.     myErr = MakeImageDescriptionForEffect(theEffectType, &mySampleDesc);
  739.     if (myErr != noErr)
  740.         return(nil);
  741.  
  742.     // fill in the fields of the sample description
  743.     (**mySampleDesc).width = theWidth;
  744.     (**mySampleDesc).height = theHeight;
  745.  
  746.     return(mySampleDesc);
  747. }
  748.  
  749.  
  750. void PrepareDecompressionSequence (void)
  751. {
  752.     HLock((Handle) gEffectDesc);
  753.  
  754.     DecompressSequenceBeginS(&gEffectSequenceID,
  755.                     gSampleDescription,
  756.                     StripAddress(*gEffectDesc),
  757.                     GetHandleSize(gEffectDesc),
  758.                     (CGrafPtr) gMonitor,
  759.                     nil,
  760.                     nil,
  761.                     nil,
  762.                     ditherCopy,
  763.                     nil,
  764.                     0,
  765.                     codecNormalQuality,
  766.                     nil);
  767.  
  768.     HUnlock((Handle) gEffectDesc);
  769. }
  770.  
  771.  
  772.  
  773. void CopyFrameToWindow (WindowPtr inWindow)
  774. {
  775.     if (gTempFrame != NULL) {
  776.         GrafPtr            oldPort = NULL;
  777.         Rect            rWindowBounds;
  778.         Rect            srcRect;
  779.         PixMapHandle    pmhTempFrame = GetGWorldPixMap (gTempFrame);
  780.         long    frameRate;
  781.         Str255    secString;
  782.  
  783.         gNumFrames++;
  784.         if (gStartSeconds == 0) {
  785.             GetDateTime (&gStartSeconds);
  786.         } else {
  787.             GetDateTime (&gSeconds);
  788.         }
  789.         
  790.         rWindowBounds = inWindow->portRect;
  791.         srcRect = rWindowBounds;
  792.         OffsetRect (&srcRect, -srcRect.left, -srcRect.top);
  793.         
  794.         GetPort (&oldPort);
  795.         SetPort (inWindow);
  796.         
  797. //        CopyBits ((BitMap*)(*pmhTempFrame), &(inWindow->portBits), &srcRect, &rWindowBounds, srcCopy, NULL);
  798.         RunEffect (1,1);
  799.         
  800.         frameRate = gNumFrames / (gSeconds - gStartSeconds);
  801.         MoveTo (50, 50);
  802.         NumToString (frameRate, secString);
  803.         DrawString (secString);
  804.         
  805.         SetPort (oldPort);
  806.     }
  807. }
  808.  
  809.  
  810. void LinkUpSources (void)
  811. {
  812.     OSErr    myErr = noErr;
  813.     ImageSequenceDataSource     mySrc1 = 0;
  814.     PixMapHandle    pmhTempFrame = GetGWorldPixMap (gTempFrame);
  815.     
  816.     // Generate a description of the first graphics world and store it in
  817.     // gWorld1Desc
  818.     myErr = MakeImageDescriptionForPixMap(pmhTempFrame, //gWorld1->portPixMap,
  819.                                          &gSampleDescription);
  820.  
  821.     // Create a source from the graphics world description.
  822.     myErr = CDSequenceNewDataSource(gEffectSequenceID,
  823.                                 &mySrc1,
  824.                                 'srcA',
  825.                                 1,
  826.                                 (Handle)gSampleDescription,
  827.                                 nil,
  828.                                 0);
  829.  
  830.     // Set the data for source srcA to be the pixMap of the graphics
  831.     // world gWorld1
  832.     CDSequenceSetSourceData(mySrc1, GetPixBaseAddr(pmhTempFrame), (**gSampleDescription).dataSize);
  833.  
  834.     SetTimeBaseRate(gTimeBase, 0);
  835.     CDSequenceSetTimeBase(gEffectSequenceID, gTimeBase);
  836. }
  837.  
  838. // Decompress a single step of the effect sequence at time.
  839. OSErr RunEffect(TimeValue theTime, int theNumberOfSteps)
  840. {
  841.     OSErr                   err = noErr;
  842.     ICMFrameTimeRecord      frameTime;
  843.     
  844.     // Set the timebase time to the step of the sequence to be rendered
  845.     SetTimeBaseValue(gTimeBase, theTime, theNumberOfSteps);
  846.  
  847.     frameTime.value.lo      = theTime;
  848.     frameTime.value.hi      = 0;
  849.     frameTime.scale         = theNumberOfSteps;
  850.     frameTime.base          = 0;
  851.     frameTime.duration      = theNumberOfSteps;
  852.     frameTime.rate          = 0;
  853.     frameTime.recordSize    = sizeof(frameTime);
  854.     frameTime.frameNumber   = 1;
  855.     frameTime.flags         = icmFrameTimeHasVirtualStartTimeAndDuration;
  856.     frameTime.virtualStartTime.lo   = 0;
  857.     frameTime.virtualStartTime.hi   = 0;
  858.     frameTime.virtualDuration   = theNumberOfSteps;
  859.  
  860.     HLock(gEffectDesc);
  861.     DecompressSequenceFrameWhen(gEffectSequenceID,
  862.                             StripAddress(*gEffectDesc),
  863.                             GetHandleSize(gEffectDesc),
  864.                             0,
  865.                             0,
  866.                             nil,
  867.                             &frameTime);
  868.     HUnlock(gEffectDesc);
  869. }
  870.  
  871.  
  872.  
  873. void GetSkinTone (RGBColor* prgbColor)
  874. {
  875.     NColorPickerInfo    pickInfo;
  876.     
  877.     SGPause (gSeqGrabber, 1);
  878.     
  879.     BlockZero (&pickInfo, sizeof (pickInfo));
  880.     
  881.     pickInfo.theColor.color.rgb.red = 40000;
  882.     pickInfo.theColor.color.rgb.green = 25000;
  883.     pickInfo.theColor.color.rgb.blue = 15000;
  884.     pickInfo.dstProfile = NULL;
  885.     pickInfo.flags = kColorPickerDialogIsMoveable | kColorPickerDialogIsModal;
  886.     pickInfo.placeWhere = kCenterOnMainScreen;
  887.     pickInfo.dialogOrigin.h = 0;
  888.     pickInfo.dialogOrigin.v = 0;
  889.     pickInfo.pickerType = 0;
  890.     pickInfo.eventProc = NULL;
  891.     pickInfo.colorProc = NULL;
  892.     pickInfo.colorProcData = 0;
  893.     pickInfo.prompt [ 0 ] = 0;
  894.     pickInfo.reserved = 0;
  895.     
  896.     NPickColor (&pickInfo);
  897.     
  898.     prgbColor->red = pickInfo.theColor.color.rgb.red;
  899.     prgbColor->green = pickInfo.theColor.color.rgb.green;
  900.     prgbColor->blue = pickInfo.theColor.color.rgb.blue;
  901.     
  902.     MakeEffectDescription ();
  903.     gSampleDescription = MakeSampleDescription (kWhichEffect, 720, 480);
  904.     PrepareDecompressionSequence ();
  905.     LinkUpSources ();
  906.     
  907.     SGPause (gSeqGrabber, 0);
  908.     
  909.     GetDateTime (&gStartSeconds);
  910.     gNumFrames = 0;
  911. }
  912.  
  913.  
  914.  
  915. void ToggleParentalFilter (void)
  916. {
  917.     SGPause (gSeqGrabber, 1);
  918.  
  919.     gParental = !gParental;
  920.  
  921.     MakeEffectDescription ();
  922.     gSampleDescription = MakeSampleDescription (kWhichEffect, 720, 480);
  923.     PrepareDecompressionSequence ();
  924.     LinkUpSources ();
  925.     
  926.     SGPause (gSeqGrabber, 0);
  927.     
  928.     GetDateTime (&gStartSeconds);
  929.     gNumFrames = 0;    
  930. }
  931.